﻿/* ============================================================================
(c) Copyright 2012 Hewlett-Packard Development Company, L.P.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge,publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
============================================================================ */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.IO;
using HPCloud.Common.Properties;
using System.Collections.ObjectModel;
using HPCloud.Common;
using System.Diagnostics.Contracts;
using System.Web;

namespace HPCloud.Objects.Domain
{
    public class StoragePath
    {
        const string cFolderMarker = "folder.txt";
        private string _storageManagementURI;
        private string _path;
        private PathType _pathType;
        private string _volume;
        private string _fileName;

//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="drive">The KvsDriveInfo instance</param>
/// <param name="path">The path to the resource</param>
//=======================================================================================================
        public StoragePath(string dnsPortion, string volume, string path)
        {
            Contract.Requires(dnsPortion != null);
            Contract.Requires(volume != null);
            Contract.Requires(path != null);

            string absoluteURI;
            if (volume != "")
                absoluteURI = dnsPortion + "/" + volume + "/" + path;
            else
                absoluteURI = dnsPortion + "/" + path;
                        
            _pathType = this.GetPathType(absoluteURI);

            if (_pathType == Common.PathType.Remote)
            {
                _storageManagementURI = this.GetPathSubstring(absoluteURI, 2);
                string resourcePath   = volume + "/" + path;
                _volume               = volume;
                _path                 = path;
                _fileName             = System.IO.Path.GetFileName(_path);
            }
            else
            {
                _volume   = volume;
                _path     = path;
                _fileName = System.IO.Path.GetFileName(_path);
            }
            _volume = volume;
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="drive">The KvsDriveInfo instance</param>
/// <param name="path">The path to the resource</param>
//=======================================================================================================
        //public StoragePath(string absoluteURI, string volume)  
        //{
        //    Contract.Requires(absoluteURI != null);

        //    _pathType = this.GetPathType(absoluteURI);

        //    if (_pathType == Common.PathType.Remote)
        //    {
        //        _storageManagementURI = this.GetPathSubstring(absoluteURI, 2);
        //        string resourcePath   = absoluteURI.Substring(absoluteURI.IndexOf(volume));
        //        _volume               = volume;
        //        _path                 = absoluteURI.Replace(_storageManagementURI + "/", String.Empty);
        //        _fileName             = System.IO.Path.GetFileName(_path);
        //    }
        //    else
        //    {
        //        _volume   = volume;
        //        _path     = absoluteURI.Replace(_volume, String.Empty).Substring(1);
        //        _fileName = System.IO.Path.GetFileName(_path);
        //    }
        //   _volume = volume;           
        //}
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="drive">The KvsDriveInfo instance</param>
/// <param name="path">The path to the resource</param>
//=======================================================================================================
        public StoragePath(string absoluteURI)
        {
            this.Initialize(absoluteURI);
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="absoluteURI"></param>
//=======================================================================================================
        private void Initialize(string absoluteURI)
        {
            Contract.Requires(absoluteURI != null);

            _pathType = this.GetPathType(absoluteURI);

            if (_pathType == Common.PathType.Remote)
            {
                _storageManagementURI = this.GetPathSubstring(absoluteURI, 2);
                string resourcePath   = absoluteURI.Replace(_storageManagementURI, String.Empty).Substring(1);
                _volume               = StoragePath.GetFirstPathElement(resourcePath);
                _path                 = absoluteURI.Replace(_storageManagementURI + "/" + _volume, String.Empty).Substring(1);
                _fileName             = System.IO.Path.GetFileName(_path);
            }
            else
            {
                _volume   = StoragePath.GetFirstPathElement(absoluteURI);
                _path     = absoluteURI.Replace(_volume, String.Empty).Substring(1);
                _fileName = System.IO.Path.GetFileName(_path);
            }
        }
//==================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
//==================================================================================================
        private string ExtractPattern(string path)
        {
            path = path.TrimEnd('/');
            string[] elements = path.Split('/');
            return elements[elements.Length - 1];
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public bool IsRoot
        {
            get
            {
                if (this.ContainsWildcard)

                    if (this.GetDirectoryName().Replace(this.ExtractPattern(this.Path), String.Empty) == String.Empty)
                        return true;
                    else
                        return false;
                return false;
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public bool ContainsWildcard
        {
            get
            {
                if (this.Path.Contains("?") || this.Path.Contains("*") || this.Path.Contains("[") || this.Path.Contains("]"))
                    return true;
                else
                    return false;
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
//=======================================================================================================
        private string CleanVolumeName(string name)
        {
            string storageContainerName = name.Replace("/", "");
            int index         = storageContainerName.IndexOf(":");

            if (index != -1)
                storageContainerName = storageContainerName.Remove(index, 1);

            return storageContainerName.Replace(@"\", "").Trim();
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
//=======================================================================================================
        private string CleanPath(string path)
        {
            string tempPath = path.Replace(@"\", "/");

            if (path.StartsWith("/"))
            {
                tempPath = tempPath.Substring(1);
            }

            // If this is not a folder path, extract out the filename..

            if (!tempPath.EndsWith("/"))
            {
                _fileName = System.IO.Path.GetFileName(tempPath);
            }
            return tempPath;
        }
        #region Properties
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public PathType PathType
        {
            get { return _pathType; }
            //set { _pathType = value; }
        }
        #endregion
        #region Methods
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <returns></returns>
//=======================================================================================================
        public string GetDirectoryName()
        {
            return System.IO.Path.GetDirectoryName(this.Path);
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
//=======================================================================================================
        private string GetPathSubstring(string element, int offset)
        {
            bool isSecure = false;

            if (element.StartsWith("https://"))
            {
                element = element.Replace("https://", string.Empty);
                isSecure = true;
            }
            else
            {
                element = element.Replace("http://", string.Empty);
            }
            string [] elements = element.Split('/');
            string result = null;

            for (int i = 0; i <= offset; ++i) {
                result = result + "/" + elements[i];                            
            }

            if (isSecure)
            {
                return "https:/" + result;
            }
            else
            {
                return "http:/" + result;
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
//=======================================================================================================
        public static string GetFirstPathElement(string element)
        {
            if (element != string.Empty)
            {
                if (element.StartsWith("/"))
                {
                    int delimeterPosition = element.IndexOf("/", 1, StringComparison.Ordinal);
                    if (delimeterPosition != -1)
                        return element.Substring(0, delimeterPosition);
                    else
                        return null;
                }
                else
                {
                    int delimeterPosition = element.IndexOf("/", 0, StringComparison.Ordinal);
                    if (delimeterPosition != -1)
                        return element.Substring(0, delimeterPosition);
                    else
                    {
                        // No / delimiters exist. This is a local file path with \ as the delimiter so parse with that in mind..

                        int delimeterPosition2 = element.IndexOf(@"\", 0, StringComparison.Ordinal);
                        if (delimeterPosition2 != -1)
                            return element.Substring(0, delimeterPosition2);

                    }
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
//=========================================================================================
/// <summary>
/// 
/// </summary>
//=========================================================================================
        public bool IsFolderPathOnly
        {
            get
            {
                if (_path.EndsWith("/") || _path.EndsWith(@"\") || _path == "")
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
////=========================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="resourcePath"></param>
/// <returns></returns>
//=========================================================================================
        private bool IsLocalPath(string volume)
        {
            // Temporaily reverse the delimiter for this check...

            List<DriveInfo> drives = DriveInfo.GetDrives().ToList<DriveInfo>();

            drives.DefaultIfEmpty(null);
            if (drives.Where(d => volume.ToUpper().Contains(d.Name)).FirstOrDefault() == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
//=======================================================================================================
        private PathType GetPathType(string absoluteURI)
        {
            if (absoluteURI.StartsWith("http:") || absoluteURI.StartsWith("https:"))
                return Common.PathType.Remote;
            else
                return Common.PathType.Local;
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public string BasePath
        {
            get
            {
                string[] absolutePath = this.AbsoluteURI.Split('/');
                List<string> basePath = new List<string>();

                //for (int i = 0; i < 3; i++) {
                for (int i = 0; i <= absolutePath.Length - 1; i++)
                {
                    basePath.Add(absolutePath[i]);
                }

                return String.Join("/", basePath);
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public string ContainerPath
        {
            get
            {
                return _storageManagementURI + "/" + _volume + "/";
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>-
/// <returns></returns>
//=======================================================================================================
        public string FileName
        {
            get
            {
                if (this.IsFolderPathOnly)
                    return string.Empty;
                else
                    return _fileName;
            }
            set
            {
                string[] tempPath = _path.Split('/');
                tempPath[tempPath.Length - 1] = value;
                _path = String.Join("/", tempPath);
                _fileName = value;
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public string Volume
        {
            get
            {
               return _volume;
            }
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
//=======================================================================================================
        public string LeafFolder
        {
            get
            {
                string tempPath = null;
                if (this.Path.EndsWith("/") || this.Path.EndsWith(@"\"))
                {
                    tempPath = this.Path.Substring(0, this.Path.Count() - 1 );
                }
                else
                {
                    tempPath = this.Path;
                }

                string[] elements = tempPath.Replace(@"\", "/").Split('/');

                if (elements.Count() == 1)
                {
                    return elements[0];
                }
                else if (elements.Count() == 0)
                {
                    return "/";
                }
                else if (elements.Count() > 1)
                {
                    string leaf = elements[elements.Count() - 1];
                    return leaf + "/";
                }
                return "";
            }
        }
//=======================================================================================================
/// <summary>
/// This is the address to the Object starting AFTER the storageContainer name. If this points to an object, that
/// object name will still be in this path..
/// </summary>
//=======================================================================================================
        public string Path
        {
            get
            {
                if (_path.StartsWith(@"\") || _path.StartsWith("/"))
                {
                    return _path.Substring(1);
                    //return _path;
                }
                else
                {
                    return _path;
                }
            }
        }
//=======================================================================================================
/// <summary>
/// Volume + Path
/// </summary>
//=======================================================================================================
        public string ResourcePath
        {
            get
            {
                if (_pathType == Common.PathType.Remote)

                    if (this.Path == "/")
                    {
                        return (this.Volume + "/").Replace(@"\", "/");
                    }
                    else
                    {
                        return (this.Volume + "/" + this.Path).Replace(@"\", "/").Replace("//", "/");                        
                    }
                else
                    return this.Volume + @"\" + this.Path;
            }
        }
//=======================================================================================================
/// <summary>
/// DNS Address + Volume + Path
/// </summary>
//=======================================================================================================
        public string AbsoluteURI
        {
            get
            {
                if (_pathType == Common.PathType.Remote)
                {
                    //return (Settings.Default.StorageManagementURI + "/" + this.ResourcePath).Replace(@"\", "/").Replace(" ", "_");

                    if (this.ResourcePath.StartsWith("/"))
                        return (_storageManagementURI +  this.ResourcePath).Replace(@"\", "/");
                    else
                        return (_storageManagementURI + "/" + this.ResourcePath).Replace(@"\", "/");
                }
                else
                {
                    return (this.Volume + @"\" + this.Path).Replace(@"\", "/");
                }
            }
        }
//=======================================================================================================
/// <summary>
/// Returns the fully qualified URI in string format.
/// </summary>
/// <returns></returns>
//=======================================================================================================
        public override string ToString()
        {
            return this.AbsoluteURI;
        }
//=======================================================================================================
/// <summary>
/// 
/// </summary>
/// <returns></returns>
//=======================================================================================================
        public Uri ToUri()
        {
            string uri;

            if (this.ResourcePath.StartsWith("/"))
            {
                uri = _storageManagementURI + this.ResourcePath;
                return new Uri(uri);
            }
            else
            {
                uri = _storageManagementURI + "/" + this.ResourcePath;
                return new Uri(uri);
            }
        }
        #endregion
    }
}
